package metrics

import (
	"fmt"
	"net/http"
	"time"

	"k8s.io/apimachinery/pkg/util/json"

	"gopkg.openfuyao.cn/cluster-api-provider-bke/utils/log"
)

type HttpResponse struct {
	Code int         `json:"code"`
	Msg  string      `json:"msg"`
	Data interface{} `json:"data,omitempty"`
}

func (res HttpResponse) bytes() ([]byte, error) {
	return json.Marshal(res)
}

func newResp(data interface{}, msg string, code int) HttpResponse {
	return HttpResponse{
		Code: code,
		Msg:  msg,
		Data: data,
	}
}

func Ok(data interface{}, msg string) ([]byte, error) {
	return newResp(data, msg, http.StatusOK).bytes()
}
func Error(msg string) ([]byte, error) {
	return newResp(nil, msg, http.StatusInternalServerError).bytes()
}
func Bad(msg string) ([]byte, error) {
	return newResp(nil, msg, http.StatusBadRequest).bytes()
}

type httpExportResponse struct {
	Name      string `json:"name"`
	StartTime string `json:"start_time"`
	EndTime   string `json:"end_time"`
	Describe  string `json:"describe"`
	Duration  int    `json:"duration"`
}

func (r *BKEClusterMetricRegister) HttpExportFunc() http.HandlerFunc {
	return func(w http.ResponseWriter, req *http.Request) {
		// 获取查询参数
		cluster := req.URL.Query().Get("cluster")
		if cluster == "" {
			res, _ := Bad("param cluster is required")
			w.Write(res)
			return
		}
		from := req.URL.Query().Get("from")
		to := req.URL.Query().Get("to")

		startTime, endTime, err := ParseTimeFromTo(from, to)
		if err != nil {
			res, _ := Bad(fmt.Sprintf("parse time error: %v", err))
			log.Errorf("parse time error: %v", err)
			w.Write(res)
			return
		}
		log.Debugf("gather cluster: %q from %q to %q", cluster, startTime, endTime)

		metricsGather, err := r.Gather(cluster, PhaseDurationSeconds, NodeBootstrapDurationSeconds)
		if err != nil {
			res, _ := Error(fmt.Sprintf("gather cluster: %s, error: %v", cluster, err))
			w.Write(res)
			return
		}

		metricsGather = filterMetricsData(metricsGather, startTime, endTime)

		resp := make([]httpExportResponse, 0)
		for name, metrics := range metricsGather {
			switch name {
			case PhaseDurationSeconds:
				for _, metric := range metrics {
					respItem := httpExportResponse{
						Name:      metric["phase"],
						StartTime: metric["start_time"],
						EndTime:   metric["end_time"],
						Describe:  metric["describe"],
						Duration:  calculateTimeDifference(metric["start_time"], metric["end_time"]),
					}
					resp = append(resp, respItem)
				}
			case NodeBootstrapDurationSeconds:
				//[]string{"node", "role", "boot_success", "start_time", "end_time"},
				for _, metric := range metrics {
					respItem := httpExportResponse{
						Name:      metric["node"],
						StartTime: metric["start_time"],
						EndTime:   metric["end_time"],
						Describe:  fmt.Sprintf("node: %s, bootstrap success: %s", metric["node"], metric["boot_success"]),
						Duration:  calculateTimeDifference(metric["start_time"], metric["end_time"]),
					}
					resp = append(resp, respItem)
				}
			default:

			}
		}

		res, _ := Ok(resp, "export success")
		if _, err = w.Write(res); err != nil {
			log.Errorf("write resp error: %v", err)
			return
		}

	}
}

func (r *BKEClusterMetricRegister) HttpClusterFunc() http.HandlerFunc {
	return func(writer http.ResponseWriter, request *http.Request) {
		resp := []string{}

		r.mux.RLock()
		for clusterName, _ := range r.collectors {
			resp = append(resp, clusterName)
		}
		r.mux.RUnlock()

		res, _ := Ok(resp, "success")
		writer.Write(res)
	}
}

// calculateTimeDifference 计算时间差值单位为s，不足1s为0
func calculateTimeDifference(startTimeStr, endTimeStr string) int {

	// 解析开始时间和结束时间
	startTime, err := time.Parse(TimeFormat, startTimeStr)
	if err != nil {
		log.Warnf("Error parsing start time:", err)
		return 0
	}

	endTime, err := time.Parse(TimeFormat, endTimeStr)
	if err != nil {
		log.Warnf("Error parsing end time:", err)
		return 0
	}

	// 计算时间差值（单位为秒）
	duration := endTime.Sub(startTime)
	seconds := int(duration.Seconds())

	// 如果时间差值小于1秒，则返回0
	if seconds < 1 {
		return 0
	}

	return seconds
}

func filterMetricsData(metricsGather map[string][]map[string]string, start, end time.Time) map[string][]map[string]string {
	res := make(map[string][]map[string]string)

	for name, gatherMetrics := range metricsGather {
		resItem := make([]map[string]string, 0)
		for _, metric := range gatherMetrics {

			startTime := metric["start_time"]
			endTime := metric["end_time"]

			if startTime == "" || endTime == "" {
				// 如果没有相关时间字段直接跳过就好
				continue
			}
			// 判断是否在时间范围内

			startTimeTime, _ := time.Parse(TimeFormat, startTime)
			endTimeTime, _ := time.Parse(TimeFormat, endTime)
			// time.Parse() 解析出来的时间time.Time 不带时区（UTC），
			// 但是这个时间（startTime\endTime）本身是加了时区偏移后的时间，程序中所有的时间都是上海时区
			// 所以有这奇怪的一坨
			if startTimeTime.Local().Add(-8*time.Hour).After(start) && endTimeTime.Local().Add(-8*time.Hour).Before(end) {
				resItem = append(resItem, metric)
			}
		}
		res[name] = resItem
		log.Debugf("gather vec: %q %d match time range", name, len(resItem))
	}

	return res
}
